package org.mokusakura.persistence.Util;

import org.mokusakura.constant.SystemSettingsConstant;

import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URLEncoder;
import java.util.Map;

/**
 * @author MokuSakura
 */
public class RedirectUtil {
    private static final String PARAMETERS_STARTS_STRING = "?";
    private static final String PARAMETERS_SEPARATOR = "&";
    private static final String KEY_VALUE_SEPARATOR = "=";
    private static final int EACH_PARAMETER_AVERAGE_LENGTH = 20;

    /**
     * @param servletContext servletContext
     * @param servletUrl     servletUrl
     * @return The string to redirect
     */
    public static String getRedirectString(ServletContext servletContext, String servletUrl) {
        return servletContext.getContextPath() + servletUrl;
    }


    /**
     * This will send direct without any parameters.
     *
     * @param request   request
     * @param response  response
     * @param url       Absolute url starting from the root of the project
     * @param encodeUri Whether to encode url parameter as url patterns
     * @throws IOException May caused by {@code request}, {@code response} or {@code url} is {@code null}
     *                     or {@code url} is an empty string.
     */
    public static void sendRedirect(HttpServletRequest request, HttpServletResponse response, String url,
                                    boolean encodeUri) throws IOException {
        checkNull(request, response, url);
        url = request.getContextPath() + url;
        if (encodeUri) {
            url = URLEncoder.encode(url, SystemSettingsConstant.SYSTEM_CHARACTER_ENCODE_TYPE);
        }

        response.sendRedirect(url);
    }

    /**
     * This will send direct with parameters.
     *
     * @param request    request
     * @param response   response
     * @param url        Absolute url starting from the root of the project
     * @param encodeUri  Whether to encode url parameter as url patterns
     * @param parameters parameters will be encode into url
     * @throws IOException May caused by {@code request}, {@code response} or {@code url} is {@code null}
     *                     or {@code url} is an empty string.
     */
    public static void sendRedirect(HttpServletRequest request, HttpServletResponse response, String url,
                                    boolean encodeUri,
                                    Map<String, String> parameters) throws IOException {
        checkNull(request, response, url);
        url = request.getContextPath() + url;
        if (parameters != null && !parameters.isEmpty()) {
            url += encodeParameters(parameters);
        }
        response.sendRedirect(url);
    }

    private static String encodeParameters(Map<String, String> parameters) {
        StringBuilder stringBuilder = new StringBuilder(PARAMETERS_STARTS_STRING);
        stringBuilder.ensureCapacity(parameters.size() * EACH_PARAMETER_AVERAGE_LENGTH);
        for (Map.Entry<String, String> entry : parameters.entrySet()) {
            stringBuilder.append(entry.getKey());
            stringBuilder.append(KEY_VALUE_SEPARATOR);
            stringBuilder.append(entry.getValue());
            stringBuilder.append(PARAMETERS_SEPARATOR);
        }
        return stringBuilder.deleteCharAt(stringBuilder.lastIndexOf(PARAMETERS_SEPARATOR)).toString();
    }

    private static void checkNull(HttpServletRequest request, HttpServletResponse response, String url) throws
            IOException {
        if (request == null || response == null || url == null || url.isEmpty()) {
            throw new IOException();
        }
    }
}
